define(['jquery', 'pixi', 'io', 'game', 'sound'], function ($, pixi, io, game, sound) {

    // 延迟调用辅助类
    let DelayCall = function (delay) {
        let timer = null;

        let invoke = function (func) {
            if (timer == null) {
                timer = setTimeout(function () {
                    func();
                    timer = null;
                }, delay);
            }
        };

        this.timer = timer;
        this.invoke = invoke;
    };

    // --------------- ------------------- --------------------

    let app = null;
    // 游戏背景音乐
    let bgMusic;
    // 玩家
    let P1, P2;
    // 初始化参数
    let startArgs;
    // 移动误差
    let adjust = 20;
    // 游戏速度(单位为毫秒,数字越小,难度越高)
    var interval = 300;
    var timer;

    // --------------- ------------------- --------------------

    var bindEvent = function (socket, player) {
        // 键盘事件
        $('body').bind('keydown', function (e) {
            if (e.keyCode == 38 || e.keyCode == 87) { // up, W
                player.rotate();
                socket.emit('rotate', {});
            } else if (e.keyCode == 39 || e.keyCode == 68) { // right, D
                player.right();
                socket.emit('right', {});
            } else if (e.keyCode == 40 || e.keyCode == 83) { // down, S
                player.down();
                socket.emit('down', {});
            } else if (e.keyCode == 37 || e.keyCode == 65) { // left, A
                player.left();
                socket.emit('left', {});
            } else if (e.keyCode == 32) { // space
                player.fall();
                socket.emit('fall', {});
            }
        });

        // 触屏事件
        if (app.stage.interactive != true) {
            app.stage.interactive = true;

            let delay = new DelayCall(50);
            let dragging = false,
                data = null,
                x, y;
            app.stage.on('pointerdown', function (e) {
                data = e.data;
                dragging = true;
                let pos = data.getLocalPosition(app.stage);
                x = pos.x;
                y = pos.y;
            });
            app.stage.on('pointerup', function () {
                dragging = false;
                data = null;
            });
            app.stage.on('pointermove', function () {
                if (dragging) {
                    let newPosition = data.getLocalPosition(app.stage);
                    let deltaX = x - newPosition.x;
                    let deltaY = y - newPosition.y;
                    delay.invoke(function () {
                        moveTo(socket, player, deltaX, deltaY);
                    });
                }
            });
        }
    };

    // 解绑
    var unbindEvent = function () {
        $('body').unbind('keydown');
        app.stage.off('pointerdown');
        app.stage.off('pointerup');
        app.stage.off('pointermove');
        app.stage.interactive = false;
    };

    // 绑定Socket事件
    let bindSocket = function (socket, player) {

        socket.on('leave', function () {
            // 对方掉线,停止游戏
            stop(socket);
        });

        socket.on('next', function (args) {
            console.log(player.id + ' next');
            player.generateNext(args.type, args.index);
        });

        socket.on('rotate', function () {
            console.log(player.id + ' rotate');
            player.rotate();
        });

        socket.on('right', function () {
            console.log(player.id + ' right');
            player.right();
        });

        socket.on('down', function () {
            console.log(player.id + ' down');
            player.down();
        });

        socket.on('left', function () {
            console.log(player.id + ' left');
            player.left();
        });

        socket.on('fall', function () {
            console.log(player.id + ' fall');
            player.fall();
        });

        socket.on('fixed', function () {
            console.log(player.id + ' fixed');
            player.fixed();
        });

        socket.on('clear', function () {
            console.log(player.id + ' clear');
            game.checkClear();
        });

        socket.on('over', function () {
            console.log('游戏结束');
            stop(socket);
        });
    };

    // 解绑
    let unbindSocket = function (socket) {
        socket.off("leave");
        socket.off("next");
        socket.off("rotate");
        socket.off("right");
        socket.off("down");
        socket.off("left");
        socket.off("fall");
        socket.off("fixed");
        socket.off("clear");
        socket.off("over");
    };

    // --------------- ------------------- --------------------

    // play
    var play = function (player, socket) {
        if (!player.down() && player.fixed()) {
            socket.emit('fixed', {});

            var lines = game.checkClear();
            if (lines > 0) {
                // TODO:加分
                socket.emit('clear', {});
            }

            var gameOver = game.checkGameOver();
            if (gameOver) {
                game.gameOver(false);
                socket.emit('over', false);
                stop(socket);
            } else {
                var next = genNext();
                player.generateNext(next.type, next.index);
                socket.emit('next', next);
            }
        } else {
            socket.emit('down', {});
        }
    };

    // 移动方块
    function moveTo(socket, player, x, y) {
        let abx = Math.abs(x),
            aby = Math.abs(y);

        if (abx > aby) { // 水平方向
            if (abx > adjust) {
                if (x > 0) { // 左移
                    player.left();
                    socket.emit('left', {});
                } else { // 右移
                    player.right();
                    socket.emit('right', {});
                }
            }
        } else if (abx < aby) { // 竖直方向
            if (aby > adjust) {
                if (y > 0) { // 上移
                    player.rotate();
                    socket.emit('rotate', {});
                } else { // 下移
                    player.down();
                    socket.emit('down', {});
                }
            }
        }

        // 没有动
    }

    // genNext
    var genNext = function () {
        return {
            type: Math.ceil(Math.random() * 7),
            index: Math.ceil(Math.random() * 4) - 1
        }
    };

    // --------------- ------------------- --------------------

    // 开始
    var start = function (url) {
        // 初始化游戏
        app = game.init();

        // 初始化背景音乐
        let player = new sound.SoundPlayer();
        bgMusic = player.add('bgm', 'sound/bgmusic.mp3', true);

        // 连接服务端
        var socket = io.connect(url, {'reconnect': false});

        socket.on('connect', function () {
            console.log('Client has connected to the server!');

            // 初始化第一个方块
            startArgs = genNext();
            socket.emit('start', {type: startArgs.type, index: startArgs.index});
        });

        socket.on('disconnect', function () {
            console.log('Client has disconnected to the server!');
            socket.close();
            stop(socket);
        });

        socket.on('connect_failed', function () {
            console.log('连接失败...');
        });

        socket.on('error', function () {
            console.log('错误发生...');
        });

        socket.on('wait', function (args) {
            console.log("等待其他玩家加入...");

            // P1开始准备开始游戏(此时args == startArgs)
            P1 = game.createPlayer(args.type, args.index);
            bindEvent(socket, P1);
        });

        socket.on('start', function (args) {

            bgMusic.play();

            if (P1) { // 玩家为P1
                P2 = game.createPlayer(args.type, args.index);
                bindSocket(socket, P2);

                let next = genNext();
                P1.generateNext(next.type, next.index);
                socket.emit('next', {type: next.type, index: next.index});

                // 游戏正式开始
                timer = setInterval(function () {
                    play(P1, socket);
                }, interval);

            } else { // 玩家为P2
                P1 = game.createPlayer(args.type, args.index);
                bindSocket(socket, P1);

                P2 = game.createPlayer(startArgs.type, startArgs.index);
                bindEvent(socket, P2);

                let next = genNext();
                P2.generateNext(next.type, next.index);
                socket.emit('next', {type: next.type, index: next.index});

                // 游戏正式开始
                timer = setInterval(function () {
                    play(P2, socket);
                }, interval);
            }
        });

    };

    // stop
    var stop = function (socket) {

        bgMusic.pause();

        if (timer) {
            clearInterval(timer);
            timer = null;
        }

        unbindEvent();
        unbindSocket(socket);

        startArgs = null;
        P1 = null;
        P2 = null;
    };

    // 导出
    return {
        start: start
    };
});